package com.mysecurity.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

/**
 * JWT工具类
 *
 * @author LILIBO
 * @since 2021-06-24
 */
public class JWTUtil {

    /**
     * 有效期
     */
    public static final Long JWT_TTL = 60 * 60L; // 一个小时

    /**
     * 秘钥明文
     */
    public static final String JWT_KEY = "KTJIAOYU";

    /**
     * 发行人
     */
    public static final String JWT_ISSUER = "KTJIAOYU";

    /**
     * 生成JWT
     *
     * @param subject 主题（可以存放JSON数据）
     * @return
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(generateUUID(), subject, JWTUtil.JWT_TTL);
        return builder.compact();
    }

    /**
     * 获取JWT构建器（使用HS256对称加密算法签名）
     *
     * @param uuid 唯一序号
     * @param subject 主题（可以存放JSON数据）
     * @param ttlMillis 过期时间
     * @return
     */
    private static JwtBuilder getJwtBuilder(String uuid, String subject, Long ttlMillis) {
        long nowMillis = System.currentTimeMillis();
        return Jwts.builder()
                .setId(uuid)
                .setSubject(subject)
                .setIssuer(JWTUtil.JWT_ISSUER)
                .setIssuedAt(new Date(nowMillis))
                .signWith(SignatureAlgorithm.HS256, generalKey())
                .setExpiration(new Date(nowMillis + ttlMillis * 1000L));
    }

    /**
     * 生成随机字符串UUID
     *
     * @return
     */
    public static String generateUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 生成加密后的秘钥SecretKey
     * <p>
     * 注意：打死也不要告诉别人
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getDecoder().decode(JWTUtil.JWT_KEY);
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 生成JWT
     *
     * @param subject 主题（可以存放JSON数据）
     * @param ttlMillis Token超时时间（毫秒）
     * @return
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(generateUUID(), subject, ttlMillis);
        return builder.compact();
    }

    /**
     * 生成JWT
     *
     * @param params 参数（可以存放简单的用户信息）
     * @return
     */
    public static String createJWT(Map<String, Object> params) {
        JwtBuilder builder = getJwtBuilder(generateUUID(), null, params, JWTUtil.JWT_TTL);
        return builder.compact();
    }

    /**
     * 获取JWT构建器，允许自定义参数集（使用HS256对称加密算法签名）
     *
     * @param uuid 唯一序号
     * @param subject 主题（可以存放JSON数据）
     * @param params 自定义参数集合
     * @param ttlMillis 过期时间
     * @return
     */
    private static JwtBuilder getJwtBuilder(String uuid, String subject, Map<String, Object> params, Long ttlMillis) {
        long nowMillis = System.currentTimeMillis();
        return Jwts.builder().setClaims(params).setId(uuid).setSubject(subject).setIssuer(JWTUtil.JWT_ISSUER).setIssuedAt(new Date(nowMillis)).signWith(SignatureAlgorithm.HS256, generalKey()).setExpiration(new Date(nowMillis + ttlMillis * 1000L));
    }

    /**
     * 生成JWT
     *
     * @param params 参数（可以存放简单的用户信息）
     * @param ttlMillis Token超时时间
     * @return
     */
    public static String createJWT(Map<String, Object> params, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(generateUUID(), null, params, ttlMillis);
        return builder.compact();
    }

    /**
     * 生成JWT
     *
     * @param subject 主题（可以存放JSON数据）
     * @param params 自定义参数集合
     * @return
     */
    public static String createJWT(String subject, Map<String, Object> params) {
        JwtBuilder builder = getJwtBuilder(generateUUID(), subject, params, JWTUtil.JWT_TTL);
        return builder.compact();
    }

    /**
     * 生成JWT
     *
     * @param id 唯一标记
     * @param subject 主题（可以存放JSON数据）
     * @param ttlMillis 超时时间
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(id, subject, ttlMillis);
        return builder.compact();
    }

    public static void main(String[] args) throws Exception {
        // 用户使用账号、密码完成了登录功能，从数据库中查询出了用户对象
        // 生成JWT（将ID等信息载入主题信息）
        String uid = "22"; // 用户ID
        Map<String, Object> params = new HashMap<>();
        params.put("account", "admin"); // 设置自定义参数（不要把敏感信息放到JWT中）
        // String jwtStr = createJWT(uid, params);
        String jwtStr = createJWT("1", uid, params, 10L);
        System.out.println(jwtStr);

        // 解析JWT（Token字符串）
        Claims claims = parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIyMiIsImlzcyI6IkJvQm8iLCJleHAiOjE2ODMyODAzNTEsImlhdCI6MTY4MzI4MDM0MSwiYWNjb3VudCI6IkxpTGlCbyIsImp0aSI6IjEifQ.6StSUq2w4BptGC-ImPbFYXgMt92zB8p8VSVZi3IDqvI");
        // Claims claims = parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIyMSIsImlzcyI6IkJvQm8iLCJleHAiOjE2NzY5NTU2NDMsImlhdCI6MTY3Njk1MjA0MywiYWNjb3VudCI6IkxpTGlCbyIsImp0aSI6IjRhYWVkMDc3NzQ0ZTQyNjk5NTNmYzJjZTRhNzQzZGIzIn0.Dj99vXp4CYFSudbZkAqqj-XUOFM5NHvUHIdpLESuINU");
        // Claims claims = parseJWT(jwtStr);
        System.out.println(claims);
        // 获取主题信息（将载入的ID信息提取出来）
        System.out.println(claims.getSubject());
        // 获取自定义参数
        System.out.println(claims.get("account"));
    }

    /**
     * 生成JWT
     *
     * @param id 唯一标记
     * @param subject 主题（可以是JSON格式）
     * @param params 自定义参数集合
     * @param ttlMillis token超时时间
     * @return
     */
    public static String createJWT(String id, String subject, Map<String, Object> params, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(id, subject, params, ttlMillis);
        return builder.compact();
    }

    /**
     * 解析JWT
     *
     * @param jwt JWT字符串
     * @return
     */
    public static Claims parseJWT(String jwt) {
        return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(jwt).getBody();
    }

}